package com.dataexa.ky.service.mxgraph.analyzer;

import com.dataexa.ky.service.mxgraph.bo.*;

import java.util.*;

import com.dataexa.ky.service.mxgraph.bo.MxGraph.MxElement;
import com.dataexa.ky.service.mxgraph.bo.MxGraph.Rect;
import com.dataexa.ky.service.mxgraph.bo.MxGraph.RoundRect;
import com.dataexa.ky.service.mxgraph.bo.MxGraph.Ellipse;
import com.dataexa.ky.service.mxgraph.bo.MxGraph.Text;
import com.dataexa.ky.service.mxgraph.bo.MxGraph.Move;
import com.dataexa.ky.service.mxgraph.bo.MxGraph.Line;
import com.dataexa.ky.service.mxgraph.bo.MxGraph.Stroke;
import com.dataexa.ky.service.mxgraph.bo.MxGraph.FillStroke;
import com.dataexa.ky.service.mxgraph.bo.MxGraph.FillColor;

public class MxGraphAnalyzer {
    // 表示图中的节点
    static class Node {
        String id; // 使用坐标和形状作为唯一标识
        String label; // 文本标签
        List<Edge> outgoingEdges = new ArrayList<>();
        List<Edge> incomingEdges = new ArrayList<>();

        Node(String id, String label) {
            this.id = id;
            this.label = label;
        }
    }

    // 表示图中的边
    static class Edge {
        Node from;
        Node to;
        Edge(Node from, Node to) {
            this.from = from;
            this.to = to;
        }
    }

    // 分析流程完整性和闭合性
    public static class AnalysisResult {
        public boolean isComplete;
        public boolean isClosed;
        public String message;

        AnalysisResult(boolean isComplete, boolean isClosed, String message) {
            this.isComplete = isComplete;
            this.isClosed = isClosed;
            this.message = message;
        }
    }

    public static AnalysisResult analyze(MxGraph graph) {
        // 提取节点和边
        Map<String, Node> nodes = new HashMap<>();
        List<Edge> edges = new ArrayList<>();
        List<MxElement> elements = graph.getElements();
        Node currentNode = null;
        List<double[]> path = new ArrayList<>();
        String currentLabel = null;

        // 第一步：提取节点和文本标签
        for (MxElement element : elements) {
            if (element instanceof Rect || element instanceof RoundRect || element instanceof Ellipse) {
                String id = generateNodeId(element);
                nodes.put(id, new Node(id, null));
            } else if (element instanceof Text) {
                Text text = (Text) element;
                String id = generateNodeIdForText(text);
                if (nodes.containsKey(id)) {
                    nodes.get(id).label = text.getStr();
                }
            } else if (element instanceof Move) {
                Move move = (Move) element;
                path.clear();
                path.add(new double[]{move.getX(), move.getY()});
            } else if (element instanceof Line) {
                Line line = (Line) element;
                path.add(new double[]{line.getX(), line.getY()});
            } else if (element instanceof Stroke || element instanceof FillStroke) {
                if (path.size() >= 2) {
                    Node from = findNearestNode(nodes, path.get(0));
                    Node to = findNearestNode(nodes, path.get(path.size() - 1));
                    if (from != null && to != null && !from.equals(to)) {
                        Edge edge = new Edge(from, to);
                        edges.add(edge);
                        from.outgoingEdges.add(edge);
                        to.incomingEdges.add(edge);
                    }
                }
            }
        }

        // 完整性检查
        boolean isComplete = true;
        StringBuilder message = new StringBuilder();

        // 检查是否有节点
        if (nodes.isEmpty()) {
            isComplete = false;
            message.append("图表中没有节点。\n");
        }

        // 检查孤立节点
        for (Node node : nodes.values()) {
            if (node.incomingEdges.isEmpty() && node.outgoingEdges.isEmpty()) {
                isComplete = false;
                message.append("节点 ").append(node.label).append(" 是孤立节点。\n");
            }
        }

        // 假设“成功”是终点，检查是否有路径到达
        Node endNode = nodes.values().stream()
                .filter(n -> "成功".equals(n.label))
                .findFirst()
                .orElse(null);
        if (endNode == null) {
            isComplete = false;
            message.append("未找到终点节点（标签为‘成功’）。\n");
        } else if (endNode.incomingEdges.isEmpty()) {
            isComplete = false;
            message.append("终点节点（‘成功’）没有入边。\n");
        }

        // 闭合性检查：检测环
        boolean isClosed = hasCycle(nodes, edges);

        if (isClosed) {
            message.append("流程图中存在环路，流程是闭合的。\n");
        } else {
            message.append("流程图中不存在环路，流程非闭合。\n");
        }

        return new AnalysisResult(isComplete, isClosed, message.toString());
    }

    // 生成节点唯一标识
    private static String generateNodeId(MxElement element) {
        if (element instanceof Rect) {
            Rect rect = (Rect) element;
            return "rect_" + rect.getX() + "_" + rect.getY();
        } else if (element instanceof RoundRect) {
            RoundRect roundRect = (RoundRect) element;
            return "roundrect_" + roundRect.getX() + "_" + roundRect.getY();
        } else if (element instanceof Ellipse) {
            Ellipse ellipse = (Ellipse) element;
            return "ellipse_" + ellipse.getX() + "_" + ellipse.getY();
        }
        return "";
    }

    // 为文本生成对应的节点 ID
    private static String generateNodeIdForText(Text text) {
        return findNearestNodeId(text.getX(), text.getY());
    }

    // 找到离坐标最近的节点
    private static Node findNearestNode(Map<String, Node> nodes, double[] point) {
        double minDistance = Double.MAX_VALUE;
        Node nearest = null;
        for (Node node : nodes.values()) {
            String[] parts = node.id.split("_");
            double nx = Double.parseDouble(parts[1]);
            double ny = Double.parseDouble(parts[2]);
            double distance = Math.sqrt(Math.pow(point[0] - nx, 2) + Math.pow(point[1] - ny, 2));
            if (distance < minDistance && distance < 50) { // 假设 50 是阈值
                minDistance = distance;
                nearest = node;
            }
        }
        return nearest;
    }

    // 找到离文本坐标最近的节点 ID
    private static String findNearestNodeId(double x, double y) {
        // 假设文本靠近某个节点
        return "node_" + x + "_" + y; // 简化处理，实际应匹配节点坐标
    }

    // 使用 DFS 检测环
    private static boolean hasCycle(Map<String, Node> nodes, List<Edge> edges) {
        Set<Node> visited = new HashSet<>();
        Set<Node> recStack = new HashSet<>();

        for (Node node : nodes.values()) {
            if (!visited.contains(node)) {
                if (dfsCycle(node, visited, recStack)) {
                    return true;
                }
            }
        }
        return false;
    }

    private static boolean dfsCycle(Node node, Set<Node> visited, Set<Node> recStack) {
        visited.add(node);
        recStack.add(node);

        for (Edge edge : node.outgoingEdges) {
            Node next = edge.to;
            if (!visited.contains(next)) {
                if (dfsCycle(next, visited, recStack)) {
                    return true;
                }
            } else if (recStack.contains(next)) {
                return true;
            }
        }

        recStack.remove(node);
        return false;
    }
}